package main

const DefaultTemplate = `
{{$ProtocolVersion := .ProtocolVersion}}
{{$ProtocolTagFunctionName := .ProtocolTagFunctionName}}

{{range .Enums}}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// enum [{{.Name}}] begin

{{if .Comment}}/*
{{.Comment}}
*/{{end}}

var {{.Name}}_Slice = []int32{
	{{range .Values}}{{.Value}},
	{{end}}
}

func {{.Name}}_Len() int {
	return len({{.Name}}_Slice)
}

{{if .Enable0}}
func Check_{{.Name}}_I(value int32) bool {
	if _, ok := {{.Name}}_name[value]; ok {
		return true
	}
	return false
}
{{else}}
func Check_{{.Name}}_I(value int32) bool {
	if _, ok := {{.Name}}_name[value]; ok && value != 0 {
		return true
	}
	return false
}
{{end}}

func Check_{{.Name}}(value {{.Name}}) bool {
	return Check_{{.Name}}_I(int32(value))
}

func Each_{{.Name}}(f func({{.Name}}) bool) {
	for _, value := range {{.Name}}_Slice {
		if !f({{.Name}}(value)) {
			break
		}
	}
}

func Each_{{.Name}}_I(f func(int32) bool) {
	for _, value := range {{.Name}}_Slice {
		if !f(value) {
			break
		}
	}
}
// enum [{{.Name}}] end
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
{{end}}

{{range .Messages}}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// message [{{.Name}}] begin
{{if .ID}}
/*
{{.Comment}}
*/
type {{.Name}} struct {
    {{$ProtocolVersion}}.MessageHead
    {{.ProtoName}}
}
{{end}}

func New_{{.ProtoName}}() *{{.Name}} {
	m := &{{.Name}}{
	{{if .ID}}MessageHead: v3.MessageHead {
	        MessageID: {{.ID}},
	    },
        {{.ProtoName}}: {{.ProtoName}} {
	{{end}}
{{range .Fields}}
    {{if (eq .DescriptorProtoType "message") }}
        {{if not .IsRepeated}}
            {{if .Required}}
                {{.Name}}: New_{{.GoTypeToName}}(),
            {{end}}
        {{else}}
            {{if .Required}}
                {{.Name}}: {{.GoType}}{},
            {{end}}
        {{end}}
    {{else}}
        {{if .DefaultValue}}
            {{if not (eq .DescriptorProtoType "bytes")}}
                {{.Name}}: {{.DefaultValue}},
            {{end}}
        {{end}}
    {{end}}
{{end}}
    {{if .ID}}
        },
    {{end}}
	}
	return m
}

func (m *{{.Name}}) ResetEx() {
    {{if .ID}}
        m.MessageHead.MessageID = {{.ID}}
        m.MessageHead.MessageSeq = 0
    {{end}}
{{range .Fields}}
	{{if .IsRepeated}}
        {{if .IsMessage}}
            {{if .IsMap}}
                {{if and (not .ValueField.IsScalar) (not .ValueField.IsString) (not .ValueField.IsEnum)}}
                    {{if (ne .ValueType "[]byte")}}
                        for _, v := range m.{{.Name}} {
                            Put_{{.ValueTypeToName}}(v)
                        }
                    {{end}}
                {{end}}
	        {{else}}
                for _, e := range m.{{.Name}} {
                    Put_{{.GoTypeToName}}(e)
                }
            {{end}}
        {{end}}
        {{if .Required}}
            m.{{.Name}} = {{.GoType}}{}
        {{else}}
            m.{{.Name}} = nil
        {{end}}
	{{else}}
	    {{if .DefaultValue}}
	        {{if not (eq .DescriptorProtoType "bytes")}}
	            m.{{.Name}} = {{.DefaultValue}}
	        {{end}}
	    {{else}}
	        {{if or (eq .DescriptorProtoType "int32") (eq .DescriptorProtoType "uint32") (eq .DescriptorProtoType "int64") (eq .DescriptorProtoType "uint64") }}
                m.{{.Name}} = 0
            {{end}}
            {{if or (eq .DescriptorProtoType "sint32") (eq .DescriptorProtoType "sint64") (eq .DescriptorProtoType "fixed32") (eq .DescriptorProtoType "fixed64") (eq .DescriptorProtoType "enum")}}
                m.{{.Name}} = 0
            {{end}}
            {{if or (eq .DescriptorProtoType "bool")}}
                m.{{.Name}} = false
            {{end}}
            {{if or (eq .DescriptorProtoType "string")}}
                m.{{.Name}} = ""
            {{end}}
            {{if or (eq .DescriptorProtoType "double") (eq .DescriptorProtoType "float")}}
                m.{{.Name}} = 0.0
            {{end}}
	    {{end}}
        {{if or (eq .DescriptorProtoType "bytes") }}
            {{if .Required}}
                m.{{.Name}} = []byte{}
            {{else}}
                m.{{.Name}} = nil
            {{end}}
        {{end}}
        {{if or (eq .DescriptorProtoType "message") }}
            {{if .Required}}
                if m.{{.Name}} != nil {
                    m.{{.Name}}.ResetEx()
                } else {
                    m.{{.Name}} = Get_{{.GoTypeToName}}()
                }
            {{else}}
                if m.{{.Name}} != nil {
                    Put_{{.GoTypeToName}}(m.{{.Name}})
                    m.{{.Name}} = nil
                }
            {{end}}
        {{end}}
	{{end}}
{{end}}
}

func (m *{{.Name}}) Clone() *{{.Name}} {
	if m == nil {
		return nil
	}
	n := Get_{{.ProtoName}}()
	deriveDeepCopy{{.ProtoName}}(n, m)
	return n
}

{{if .ID}}
func (this *{{.Name}}) Equal(that *{{.Name}}) bool {
	return deriveEqual{{.Name}}(this, that)
}

func ({{.Name}}) {{$ProtocolTagFunctionName}}() {
}

func (m {{.Name}}) Head() {{$ProtocolVersion}}.MessageHead {
	return m.MessageHead
}

func {{.ProtoName}}_MessageID() {{$ProtocolVersion}}.MessageID {
	return {{.ID}}
}

func (m *{{.Name}}) SetMessageSeq(seq {{$ProtocolVersion}}.MessageSeq) {
	m.MessageHead.MessageSeq = seq
}

func ({{.Name}}) ResponseMessageID() {{$ProtocolVersion}}.MessageID {
{{if .Response}}
	return {{.Response}}_MessageID()
{{else}}
	return 0
{{end}}
}

func {{.ProtoName}}_ResponseMessageID() {{$ProtocolVersion}}.MessageID {
{{if .Response}}
	return {{.Response}}_MessageID()
{{else}}
	return 0
{{end}}
}

func ({{.Name}}) Once() bool {
{{if .Once}}
	return true
{{else}}
	return false
{{end}}
}

func {{.ProtoName}}_Once() bool {
{{if .Once}}
    return true
{{else}}
    return false
{{end}}
}

func ({{.Name}}) MinInterval() time.Duration {
    return {{.MinInterval}} * time.Millisecond
}

func {{.ProtoName}}_MinInterval() time.Duration {
	return {{.MinInterval}} * time.Millisecond
}
{{end}}

{{if .Slice}}
type {{.Name}}Slice []*{{.Name}}

func New{{.Name}}Slice() *{{.Name}}Slice {
	return &{{.Name}}Slice{}
}

func To{{.Name}}Slice(s []*{{.Name}}) *{{.Name}}Slice {
	return (*{{.Name}}Slice)(&s)
}

func (s *{{.Name}}Slice) Add() *{{.Name}} {
    if s == nil {
        return nil
    }
	return s.AddOne(Get_{{.Name}}())
}

func (s *{{.Name}}Slice) AddOne(newOne *{{.Name}}) *{{.Name}}  {
    if s == nil {
        return nil
    }
	*s = append(*s, newOne)
	return newOne
}

func (s *{{.Name}}Slice) RemoveOne(fn func(index int, element *{{.Name}}) (continued bool)) {
    if s == nil {
        return
    }
	for i, e := range *s {
		if fn(i, e) {
			*s = append((*s)[:i], (*s)[i+1:]...)
			break
		}
	}
}

func (s *{{.Name}}Slice) RemoveSome(fn func(index int, element *{{.Name}}) (continued bool)) {
    if s == nil {
        return
    }
	var left []*{{.Name}}
	for i, e := range *s {
		if !fn(i, e) {
			left = append(left, e)
		}
	}
	*s = left
}

func (s *{{.Name}}Slice) Each(fn func(index int, element *{{.Name}}) (continued bool)) {
    if s == nil {
        return
    }
	for i, e := range *s {
		if !fn(i, e) {
			break
		}
	}
}

func (s *{{.Name}}Slice) Size() int {
    if s == nil {
        return 0
    }
	return len(*s)
}

func (s *{{.Name}}Slice) Clone() (n *{{.Name}}Slice) {
	if s == nil {
		return nil
	}
	n = To{{.Name}}Slice(make([]*{{.Name}}, s.Size()))
	for i, e := range *s {
		if e != nil {
			(*n)[i] = e.Clone()
		} else {
			(*n)[i] = nil
		}
	}
	return n
}

func (s *{{.Name}}Slice) Clear() {
    if s == nil {
            return
    }
	*s = *New{{.Name}}Slice()
}
{{end}}

{{$Msg := .}}
{{range .Maps}}

type {{.Name}} map[{{.Key}}]*{{$Msg.Name}}

func To{{.Name}}(m map[{{.Key}}]*{{$Msg.Name}}) *{{.Name}} {
	if m == nil {
		return nil
	}
	return (*{{.Name}})(&m)
}

func New{{.Name}}() (m *{{.Name}}) {
	m = &{{.Name}}{}
	return
}

func (m *{{.Name}}) Get(key {{.Key}}) (value *{{$Msg.Name}}, ok bool) {
    if m == nil {
        return
    }
	value, ok = (*m)[key]
	return
}

func (m *{{.Name}}) Set(key {{.Key}}, value *{{$Msg.Name}}) {
    if m == nil {
        return
    }
	(*m)[key] = value
}

func (m *{{.Name}}) Add(key {{.Key}}) (value *{{$Msg.Name}}) {
    if m == nil {
        return
    }
	value = Get_{{$Msg.Name}}()
	(*m)[key] = value
	return
}

func (m *{{.Name}}) Remove(key {{.Key}}) (removed bool) {
    if m == nil {
        return
    }
	if _, ok := (*m)[key]; ok {
		delete(*m, key)
		return true
	}
	return false
}

func (m *{{.Name}}) RemoveOne(fn func(key {{.Key}}, value *{{$Msg.Name}}) (continued bool)) {
    if m == nil {
        return
    }
	for key, value := range *m {
		if fn(key, value) {
			delete(*m, key)
			break
		}
	}
}

func (m *{{.Name}}) RemoveSome(fn func(key {{.Key}}, value *{{$Msg.Name}}) (continued bool)) {
    if m == nil {
        return
    }
	left := map[{{.Key}}]*{{$Msg.Name}}{}
	for key, value := range *m {
		if !fn(key, value) {
			left[key] = value
		}
	}
	*m = left
}

func (m *{{.Name}}) Each(f func(key {{.Key}}, value *{{$Msg.Name}}) (continued bool)) {
	if m == nil {
        return
    }
	for key, value := range *m {
		if !f(key, value) {
			break
		}
	}
}

func (m *{{.Name}}) Size() int {
    if m == nil {
        return 0
    }
	return len(*m)
}

func (m *{{.Name}}) Clone() (n *{{.Name}}) {
	if m == nil {
		return nil
	}
	n = To{{.Name}}(make(map[{{.Key}}]*{{$Msg.Name}}, m.Size()))
	for k, v := range *m {
		if v != nil {
			(*n)[k] = v.Clone()
		} else {
			(*n)[k] = nil
		}
	}
	return n
}

func (m *{{.Name}}) Clear() {
    if m == nil {
        return
    }
    for k, _ := range *m {
        delete(*m, k)
    }
}

{{end}}

var g_{{.Name}}_Pool = sync.Pool{}

func Get_{{.ProtoName}}() *{{.Name}} {
	m, ok := g_{{.Name}}_Pool.Get().(*{{.Name}})
	if !ok {
		m = New_{{.ProtoName}}()
	} else {
		if m == nil {
			m = New_{{.ProtoName}}()
		} else {
			m.ResetEx()
		}
	}
	return m
}

func Put_{{.ProtoName}}(i interface{}) {
	if m, ok := i.(*{{.Name}}); ok && m != nil {
		g_{{.Name}}_Pool.Put(i)
	}
}

{{if .ID}}
func init() {
	Protocol.Register(
	    {{.ID}},
		&{{.Name}}{},
		func() {{$ProtocolVersion}}.IMessage { return Get_{{.ProtoName}}() },
		func(msg {{$ProtocolVersion}}.IMessage) { Put_{{.ProtoName}}(msg) },
		{{.ProtoName}}_Once(),
		{{.ProtoName}}_MinInterval(),
	)
}
{{end}}
// message [{{.Name}}] end
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
{{end}}
`
